Skip to content

Conversation

@c-morley
Copy link
Collaborator

@c-morley c-morley commented Oct 5, 2025

This is the on going work started here:
#3528
This generalizes the idea for messages.

There are three proof of concept sims:
axis_halui_test.ini
gmoccapy_halui_test.ini
qtdragon_halui_test.ini

They will load the respective gui and a separate simulated control panel.
You can notice the jograte slider on the control panel changes the jog rate on the gui.
I would love it if someone could test these rough changes.

Gstat sends out socket messages for jog rate
calls these functions in a GUI
This is a proof of concept to allow 3rd party (hal_bridge) to call
macros. The macros are run from Gmoccapy so no timing problems should
occur and and pre checks or post changes can be covered.

There needs to be agreement on where to put macro definitions in the INI.
Gmoccapy puts them under [MACROS], iniinfo under [DISPLAY]
python ZMQ module package must be available for this to work
mdi commands with a comma in it (ie MSG, text) would
not be interpeted properly
named INI MDI commands were not recognised.
you can use STATUS messages to 'press' ok or cancel
so you can use halui to accept the toolchange
so GUIs not basd in gobject can run the message system
@c-morley
Copy link
Collaborator Author

@zz912
Copy link
Contributor

zz912 commented Oct 12, 2025

Do you think that HAL between GUI and HALUI should be replaced by ZMQ in the future?
In an ideal world.

@c-morley
Copy link
Collaborator Author

Possibly but certainly not necessarily. I think the things that are very standard (say jogging, axis selection) are better done in standard way (in this case I chose HALUI) that does not require connecting HAL pins.

I would bet that non standard things would still be added using HAL pins - it's easy to do

@c-morley
Copy link
Collaborator Author

Well I said without connecting HAL pins, but I meant not connecting HAL pins from the GUI to HALUI, you still connect some HAL pins in HALUI, say for a control panel.
It just makes things standard and easier, while still allowing much customization.

@zz912
Copy link
Contributor

zz912 commented Oct 12, 2025

I always wondered why we need NML or ZMQ when theoretically we could be done via HAL?

@c-morley
Copy link
Collaborator Author

Outside my cone of hard knowledge, but as I under stand it, NML is a Neutral Message Layer for networking. I believer the idea was the GUI, IO controller and motion controller could be on different computers. Certainly the GUI side could be networked at one time.
HAL uses shared memory scheme, so can not directly be networked.

@zz912
Copy link
Contributor

zz912 commented Oct 13, 2025

What advantages does ZMQ have over HAL?

@c-morley
Copy link
Collaborator Author

In this case, zmq automically connects the gui to halui and any other program that registers to it. This creates consistent information in the system and a consistent connection path for doing jogging or axis selection.

@zz912
Copy link
Contributor

zz912 commented Oct 13, 2025

Thank you for explaining your thoughts.

Now I can get back to testing.

My test procedure:
1 ) Run gmoccapy_halui_test.ini
2 ) Turn off E-stop
3 ) Turn on machine
4 ) Home machine

Test number 1:
5 ) In the control panel press Manual
6 ) In the control panel press 0
You will see an ugly mode switch.
(If you don't see it, you have a very powerful PC and you should add G4 P10 to gui_mdi_commands)
This ugly mode switch also happens when using the classic mdi_commands too. I created a fix for it #3441 .

Test number 2:
7 ) In the control panel press MDI
8 ) In the control panel press 0
There is no problem

Test number 3:
9 ) In the control panel press AUTO
10 ) In the control panel press 0
Result:
Gmoccapy-run_gui_command-001

@zz912
Copy link
Contributor

zz912 commented Oct 13, 2025

For another test:

You must modify in INI file:
MDI_COMMAND_MACRO0 = G91; G1 Z-10

You must modify in gmoccapy.py

# =========================================================
# Coolant an mist coolant button
    def on_tbtn_flood_toggled(self, widget, data=None):
            self.command.wait_complete(30)
            self.command.mode(linuxcnc.MODE_MDI)
            self.command.wait_complete(30)
            self.command.mdi("G91 G1 X10 F200")
            self.command.wait_complete(30)
            self.command.mdi("G91 G1 Y10 F200")
            self.command.wait_complete(30)           
            self.command.mode(linuxcnc.MODE_MANUAL)
            self.command.wait_complete()

My test procedure:
1 ) Run gmoccapy_halui_test.ini
2 ) Turn off E-stop
3 ) Turn on machine
4 ) Home machine
5) go to 0 position => g90 => g0 x0z0y0
6 ) In the control panel press 0 and wait
Result:
Gmoccapy-run_gui_command-002
Everything is OK now.
7 ) In the control panel press 0 and immediately press cooling and wait for a few seconds.
Result:
Gmoccapy-run_gui_command-003
You are not in position Z-20 , because self.command.wait_complete(30) doesn't wait for gui_mdi_commands

Old mdi_commands make errors:
https://forum.linuxcnc.org/38-general-linuxcnc-questions/49445-python-command-wait-complete-does-not-wait-for-c-halui-commands

New gui_mdi_commands can be broken by another python command without any message.

@c-morley
Copy link
Collaborator Author

Ok Excellent notes. Thank you for testing!
I'll digest the information and probably ask follow up questions.

@c-morley
Copy link
Collaborator Author

test 1:
Mode switch; I guess it depends on what the macro is for. It might be annoying to have to switch back to manual mode after the macro, if the macro is primarily used in manual mode. In the gtk_action library call, there is a argument to turn off the automatic return to previous mode. We could come up with a way to control this option in the INI line. we already have a way to add a label and break up individual commands.
Also one could program GMoccapy not to change the screen widgets layout when running a macro, only after.

test3:
Is the problem that the command ran at all or the obviously useless after-the-fact error message?
In the Gmoccapy code I added for INI_COMMANDS, I didn't add mode checks, but for INI MACROs it does - it won't run less in MDI mode. The check could be added to INI_COMMANDS. I would have to dig deeper to see where the error message comes from.

Modified coolant test:
I'll dig in this deeper but:
You are using a button not intended for MDI commands, usually buttons are not sensitive when a MDI command is running

The first question is what do you think should be the right behavior?
allow/never allow 'stacked' commands from multiple sources?
cancel any running MDI command if another is imitated?
Ignore any new MDI buttons if MDI is already running

@zz912
Copy link
Contributor

zz912 commented Oct 16, 2025

Test 1
I would like to repeat that in Gmoccapy there are 3 ways to run an MDI command.
1 ) MACRO - is part of the gmoccapy.py code. The MDI command is defined in the INI file in section

[MACROS]
MACRO = i_am_lost
MACRO = halo_world
MACRO = jog_around
MACRO = increment xinc yinc
MACRO = go_to_position X-pos Y-pos Z-pos

Gmoccapy creates a button for the MACRO. It is possible to add an image to this MACRO. Unfortunately, the MACRO does not have HAL pins. That is why I do not use the MACRO.

2 ) halui.mdi_command - is part of the halui.cc code. The MDI command is defined in the INI file in section

[HALUI]
MDI_COMMAND = G10 L20 P0 X0 ( Set X to zero )
MDI_COMMAND = G10 L20 P0 Y0 ( Set Y to zero )
MDI_COMMAND = G10 L20 P0 Z0 ( Set Z to zero )

halui.mdi_command has HAL pins. Unfortunately, Gmoccapy does not create buttons for halui.mdi_command. I have to create them myself and connect them in the HAL file using net.

3 ) halui.gui_mdi_command - the MDI command is defined in the INI file in section

[MDI_COMMAND_LIST]
MDI_COMMAND_MACRO0 = G91; G1 Z-10
MDI_COMMAND_MACRO1 = G53 G0 Z0;G53 G0 X0 Y0,Goto\nMachn\nZero
MDI_COMMAND_MACRO2 = (MSG, macro 2);
MDI_COMMAND_MACRO3 = (MSG, macro 2)
MDI_COMMAND_MACRO4 = (MSG, macro 2), test

I was bothered earlier that there were two things with a similar function (MACRO and halui.mdi_command)
I would like an option for halui.mdi_command in the INI file. This option would create buttons for the selected commands in Gmoccapy and assign images. Then the MACRO would not be needed and could disappear.

I hope halui.gui_mdi_command is just a temporary workaround.
I hope there won't be 3 things with similar functionality in LCNC. (MACRO, halui.mdi_command and halui.gui_mdi_command)
It would be a complication for beginners.

I guess it depends on what the macro is for.

Often used halui.mdi_command for ATC with carousel. Most often you have physical buttons from "M6 T1" to "M6 T10". When you are in manual mode and change the tool, you want to end up in manual mode as well.
Many people mill with MPG wheel in manual mode and change the tool there too.

Test 3

I only see the problem in the unnecessary error message. If someone doesn't want to run halui.gui-mdi-command in AUTO mode, everybody can simply take care of it in HAL using the halui.mode.is-auto pin

Coolant test

You are using a button not intended for MDI commands, usually buttons are not sensitive when a MDI command is running

I use this coolant button to run the command self.command.wait_complete(30) because it is the easiest way for me to run this command in Gmoccapy. It is also the way LCNC developers can easily replicate this behavior.

The first question is what do you think should be the right behavior?
allow/never allow 'stacked' commands from multiple sources?

I would leave the choice of the right behavior to the LCNC developers. But I will write you the conditions that should be met.

  1. I don't know if the command self.command.wait_complete(30) should be used to wait for halui.gui_mdi_command to complete.
    1.1) If self.command.wait_complete(30) were to wait for halui.gui_mdi_command to complete, it would only be listed in the manual. (This I preffer)
    1.2) If self.command.wait_complete(30) did not wait for halui.gui_mdi_command to complete, then a new command should be created that can do this. For example, self.command.wait_halui_command().
    Or the original command should have a separate parameter for this. For example, self.command.wait_complete(30, H)
    1.3) If self.command.wait_complete(30) did not wait for halui.gui_mdi_command to complete, it should be mentioned in the documentation and there should be a message in the terminal that halui.gui_mdi_command was aborted. I don't know if it should be a LOG or Error message.

cancel any running MDI command if another is imitated?
Ignore any new MDI buttons if MDI is already running

This should be decided by the LCNC developer. The developer should be able to implement both abort and stack.
For this reason I created the HAL pin halui.halui-mdi-is-running.#2945

@c-morley
Copy link
Collaborator Author

reading about your mode switch patch 2945. It requires you to connect HAL pins to detect if halui commands are running. This is a hacky way to fix the problem. I'm not criticizing you for coming up with it.
I just mean it would be better to not have to connect pins to tell the GUI to wait for a third party GUI to finish what it is doing. This is where having HALUI request the runniing of MDI/macros would be a better fit (I think anyways) you only need to add code to Gmocapy to tell it to not mode switch during macros or ini MDI commands. basically what you did, without having to have a HAL pin connected for it to work.

The more you can avoid waitcomplete the better. It makes the GUI unresponsive..

For your tool buttons, could you not make oword files that just had the tool change gcode and then the macro button would be made to call the oword file?
It would not be difficult to extend the macro button idea to call plain gcode as QtDragon does.

@zz912
Copy link
Contributor

zz912 commented Oct 17, 2025

For your tool buttons, could you not make oword files that just had the tool change gcode and then the macro button would be made to call the oword file?

I dont need Gmoccapy MACRO. I need physical buttons. So I need run mdi_commands by HAL signal.

The indicator shows state, so we don't need to chow checked state.
in a real panel the buttons would be momentary buttons anyways
this must have been fix in master after I branched
@zz912
Copy link
Contributor

zz912 commented Oct 19, 2025

I have been wanting to integrate Probe screen into Gmoccapy for a long time.
I would like to modify "Probe Screen for LinuxCNC 2.9"
https://github.com/verser-git/probe_screen_v2.9

I would like to split one glade screen into several glade screens and modify PNCconf so that LCNC configuration with Gmoccapy and ProbeScreen is one click away.

The author of Probe screen also has problems with switching modes.
https://github.com/verser-git/probe_screen_v2.9/blob/main/gmoccapy_prepare/README.md

I still don't see the benefits of ZMQ and I don't understand ZMQ. I would like to ask if it would be appropriate to integrate ZMQ into Probe screen?

My point is that if I'm going to redo Probe screen, I want to do it properly.

@zz912
Copy link
Contributor

zz912 commented Oct 19, 2025

Would it be possible to send a string containing Gcode via ZMQ?

Then it would be possible to make a really useful interface for LCNC.
Then it would be possible to control LCNC meaningfully via ZMQ.
Whether it is HALUI, Probing, scientific applications that need a manipulator, a higher-level robot system, Camera object recognition, Artificial intelligence ...

zmq

@c-morley
Copy link
Collaborator Author

Yes you could send gcode via ZMQ. I don't know what the limits of the amount of data you could send at once.
I have a branch for ncam integration that uses ZMQ in Qtdragon and Gmoccapy to load the Ncam program after each update. In this case it sends a function name to call in the GUI and the arguments of the function. It works well. Not quite what you mean bit similar.

A version of versa probe is actually already in linuxcnc's repo:
https://github.com/LinuxCNC/linuxcnc/tree/master/lib/python/gladevcp/builtin-panels/versa-probe
it hasn't had any testing in a long while, so I don't know if it works properly or not.

@rmu75
Copy link
Contributor

rmu75 commented Oct 20, 2025

Seems I somehow missed that discussion. Just wanted to say I did a fairly complete POC to add a 0mq messaging layer parallel to NML, so you could run linuxcnc without any NML. see https://github.com/rmu75/linuxcnc/tree/rs/zmq-experiments.

@zz912
Copy link
Contributor

zz912 commented Oct 20, 2025

rmu75:
What does POC mean?

c-morley:

Not quite what you mean bit similar.

I dont agree. I think that halui.mdi-command, versa-probe, ncam, ...... should have same interface for GUI.
This interface should resolve issues related to mode switching and race-conditions with other commands.
I would limit the string to 128 chars, for example, so that ZMQ doesn't send long messages.
If you need to run something bigger, you'll use "o call".

@rmu75
Copy link
Contributor

rmu75 commented Oct 20, 2025

rmu75: What does POC mean?

Proof of Concept.

machinekit did add a bridge between NML and something 0mq/protobuf based, probably because they didn't want to touch the NML layer.

I wanted to explore if replacing NML would be feasible.

@c-morley
Copy link
Collaborator Author

Seems I somehow missed that discussion. Just wanted to say I did a fairly complete POC to add a 0mq messaging layer parallel to NML, so you could run linuxcnc without any NML. see https://github.com/rmu75/linuxcnc/tree/rs/zmq-experiments.

How well did it work?

@c-morley
Copy link
Collaborator Author

Not quite what you mean bit similar.

I dont agree. I think that halui.mdi-command, versa-probe, ncam, ...... should have same interface for GUI. This interface should resolve issues related to mode switching and race-conditions with other commands. I would limit the string to 128 chars, for example, so that ZMQ doesn't send long messages. If you need to run something bigger, you'll use "o call".

The interface can not resolve mode switching problems by it's self. Only the GUI programmer can do that.
What the interface changes is that it 'asks' the GUI to do something rather then doing something on it's own and hoping the GUI notices and does the right thing.

It certainly can ask the GUI to run some gcode, if that is what you want.

@zz912
Copy link
Contributor

zz912 commented Oct 20, 2025

Not quite what you mean bit similar.

I dont agree. I think that halui.mdi-command, versa-probe, ncam, ...... should have same interface for GUI. This interface should resolve issues related to mode switching and race-conditions with other commands. I would limit the string to 128 chars, for example, so that ZMQ doesn't send long messages. If you need to run something bigger, you'll use "o call".

The interface can not resolve mode switching problems by it's self. Only the GUI programmer can do that. What the interface changes is that it 'asks' the GUI to do something rather then doing something on it's own and hoping the GUI notices and does the right thing.

I thought "interface" + "modification GUI for interface" should be same for halui.mdi-command, versa-probe, ncam, ......

I thought "modification GUI for interface" should resolve issues related to mode switching and race-conditions with other commands.

It certainly can ask the GUI to run some gcode, if that is what you want.

I want:

  • ask the GUI to run some gcode
  • send string of gcode to GUI

But I'm not a Gmoccapy developer, so it doesn't matter to me.

@rmu75
Copy link
Contributor

rmu75 commented Oct 20, 2025

Seems I somehow missed that discussion. Just wanted to say I did a fairly complete POC to add a 0mq messaging layer parallel to NML, so you could run linuxcnc without any NML. see https://github.com/rmu75/linuxcnc/tree/rs/zmq-experiments.

How well did it work?

basically it does work. I tested with a minimal debug-tool https://github.com/rmu75/cockpit/tree/rs/zmq in parallel to axis & co. Overhead is slightly higher than with NML, because zeromq doesn't have a shared memory transport, so everything is serialized/desrialized into a pipe, but nothing really noticable.

The tedious part, extraction of all messages into IDL files and the writing the boilerplate code turned out to be relatively quick and easy. one central point needed changing of a pointer to std::unique_ptr because messages received via zeromq are dynamically allocated and need to be disposed of whereas NML messages always get copied to some static buffer. That change already is in master. 6d65386

The zeromq messaging layer would allow for some improved semantics of e.g. the error / warning channel, at the moment, only one consumer is allowed, if you connect more than one it is defacto undeterministic which one receives a message.

@andypugh
Copy link
Collaborator

A few notes:

I don't know if the probe-screen in the LinuxCNC repository has been updated for Python3 / Gtk3. I did that task in a fork of a fork of psng: https://github.com/andypugh/probe-screen-ng

There was a plan some time ago to replace NML with 0MQ/ZMQ. I recall a phone call from a meetup in Wichita to the original author of NML at NIST. He was astonishd that we were still using it and thought that switching to zmq was a good idea.

But that got all tangled up in the Machinekit split, and I don't think that MK ever got round to doing it.

@Sigma1912
Copy link
Contributor

@rmu75
How much work do you think your proof of concept would need to be able to be merged?

@rmu75
Copy link
Contributor

rmu75 commented Oct 21, 2025

In principle it could be merged as is, it can be run parallel to NML. Modulo bugs and things I missed. Some infrastructure / configurability and tests have to be done. Maybe alternatives to 0mq resp. flatbuffers should be evaluated before merging: (nanomsg, protocol buffers, capt'n'proto) -- flatbuffers seemed to have lower overhead compared to protobuf.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants